import 'dart:collection';
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

import 'mpc_plugin_platform_interface.dart';

/// An implementation of [MpcPluginPlatform] that uses method channels.
class MethodChannelMpcPlugin extends MpcPluginPlatform {
  /// The method channel used to interact with the native platform.
  @visibleForTesting
  final methodChannel = const MethodChannel('mpc_plugin');

  @override
  Future<Map<String, dynamic>?> getPlatformVersion() async {
    final version =
        await methodChannel.invokeMethod<String>('getPlatformVersion');
    if (version == null || version.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(version);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> getLibVersion() async {
    final version = await methodChannel.invokeMethod<String>('getLibVersion');
    if (version == null || version.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(version);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> forgingMPC(String salt, String path) async {
    Map<String, dynamic> jsonData = {
      'salt': salt,
      'path': path,
    };
    final forgingMPC = await methodChannel.invokeMethod<String>(
        'forgingMPC', jsonEncode(jsonData));
    if (forgingMPC == null || forgingMPC.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(forgingMPC);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> useMnemonicForgingMPC(
      String mne, String salt, String path) async {
    Map<String, dynamic> jsonData = {
      'salt': salt,
      'path': path,
      'mne': mne,
    };
    final useMnemonicForgingMPC = await methodChannel.invokeMethod<String>(
        'useMnemonicForgingMPC', jsonEncode(jsonData));
    if (useMnemonicForgingMPC == null || useMnemonicForgingMPC.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(useMnemonicForgingMPC);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> verifyMPCFragment(String frag) async {
    Map<String, dynamic> jsonData = {'frag': frag};
    final verifyMPCFragment = await methodChannel.invokeMethod<String>(
        'verifyMPCFragment', jsonEncode(jsonData));
    if (verifyMPCFragment == null || verifyMPCFragment.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(verifyMPCFragment);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> recoverMPCFragment(
      String frag1, String frag2) async {
    Map<String, dynamic> jsonData = {
      'frag1': frag1,
      'frag2': frag2,
    };
    final recoverMPCFragment = await methodChannel.invokeMethod<String>(
        'recoverMPCFragment', jsonEncode(jsonData));
    if (recoverMPCFragment == null || recoverMPCFragment.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(recoverMPCFragment);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> mpcEscape(
      String frag1, String frag2, String salt) async {
    Map<String, dynamic> jsonData = {
      'frag1': frag1,
      'frag2': frag2,
      'salt': salt,
    };
    final mpcEscape = await methodChannel.invokeMethod<String>(
        'mpcEscape', jsonEncode(jsonData));
    if (mpcEscape == null || mpcEscape.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(mpcEscape);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> mpcFragmentGetPublicKey(String frag) async {
    Map<String, dynamic> jsonData = {
      'frag': frag,
    };
    final mpcFragmentGetPublicKey = await methodChannel.invokeMethod<String>(
        'mpcFragmentGetPublicKey', jsonEncode(jsonData));
    if (mpcFragmentGetPublicKey == null || mpcFragmentGetPublicKey.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(mpcFragmentGetPublicKey);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> signTx(
      String tx, String mpcA, String mpcB, String salt) async {
    Map<String, dynamic> jsonData = {
      'tx': tx,
      'mpcA': mpcA,
      'mpcB': mpcB,
      'salt': salt,
    };
    final signTx = await methodChannel.invokeMethod<String>(
        'signTx', jsonEncode(jsonData));
    if (signTx == null || signTx.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(signTx);
    return map;
  }


  @override
  Future<int> getVersionFromFrag(String frag) async {
    Map<String, dynamic> jsonData = {
      'frag': frag,
    };
    final versionNo = await methodChannel.invokeMethod<String>(
        'getVersionFromFrag', jsonEncode(jsonData));

    return int.parse(versionNo.toString());
  }


  @override
  Future<Map<String, dynamic>?> getAddress(String frag, String chainId) async {
    Map<String, dynamic> jsonData = {
      'frag': frag,
      'chainId': chainId,
    };
    final addressInfo = await methodChannel.invokeMethod<String>(
        'getAddress', jsonEncode(jsonData));
    if (addressInfo == null || addressInfo.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(addressInfo);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> upgradeMPC(
      String frag1, String frag2, String salt) async {
    Map<String, dynamic> jsonData = {
      'frag1': frag1,
      'frag2': frag2,
      'salt': salt,
    };
    final forgingMPC = await methodChannel.invokeMethod<String>(
        'upgradeMPC', jsonEncode(jsonData));
    if (forgingMPC == null || forgingMPC.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(forgingMPC);
    return map;
  }

  @override
  Future<Map<String, dynamic>?> solSignTx(
      String tx, String mpcA, String mpcB, String salt) async {
    Map<String, dynamic> jsonData = {
      'tx': tx,
      'mpcA': mpcA,
      'mpcB': mpcB,
      'salt': salt,
    };
    final solSignTx = await methodChannel.invokeMethod<String>(
        'solSignTx', jsonEncode(jsonData));
    if (solSignTx == null || solSignTx.isEmpty) {
      return null;
    }
    Map<String, dynamic> map = jsonDecode(solSignTx);
    return map;
  }

}
